//!
/**
 ***********************************************************************************************************
 * <RBMathVector implementation>
 ***********************************************************************************************************
 * @file RBMathVector.cpp
 ***********************************************************************************************************/

/************************************************************************************************************
 * Includes
 ************************************************************************************************************/
#include "RBMainPCH.h"
#include "RBMathVector.h"

#include "RBBVolume.h"
#include "RBPlane.h"


/************************************************************************************************************/

namespace RBMath
{

namespace Intersect
{

void BoxesVsFrustum(int8* result, const class RBPlane* frusta, RBBVolumeHandle* boxes, uint32 count)
{
    for (uint32 ui=0; ui < count; ++ui)
    {
        RBBVolume& bv = RBBVolume::Get(boxes[ui]);

        int8 res = 1;
        for (uint32 planeIdx=0; planeIdx<6 && res != -1; ++planeIdx)
        {
            const RBPlane& plane = frusta[planeIdx];

            float nx = bv.Axes[0].Dot(plane.Normal);
            float ny = bv.Axes[1].Dot(plane.Normal);
            float nz = bv.Axes[2].Dot(plane.Normal);
 
            float dist = plane.GetDistance(bv.Center);
            float e = fabs(bv.Extents[0]*nx) + fabs(bv.Extents[1]*ny) + fabs(bv.Extents[2]*nz);
            res = (dist < -e) ? -1 : (dist < e) ? 0 : res;

        }
        result[ui] = res;

    }

}


}

float3 ProjectPointOnPlane( const RBPlane& plane, float3 point )
{
    float dist = plane.GetDistance(point);
    return point - dist * plane.Normal;
}

void ComputeFrustumPlanes( RBPlane* planes, const float4x4& viewProjection )
{
    planes[RBPlane::PF_LEFT].Normal(0) = viewProjection(3,0) + viewProjection(0,0);
    planes[RBPlane::PF_LEFT].Normal(1) = viewProjection(3,1) + viewProjection(0,1);
    planes[RBPlane::PF_LEFT].Normal(2) = viewProjection(3,2) + viewProjection(0,2);
    planes[RBPlane::PF_LEFT].Distance  = viewProjection(3,3) + viewProjection(0,3);
    RBPlane::Normalize(&planes[RBPlane::PF_LEFT]);


    // Right plane
    planes[RBPlane::PF_RIGHT].Normal(0) = viewProjection(3,0) - viewProjection(0,0);
    planes[RBPlane::PF_RIGHT].Normal(1) = viewProjection(3,1) - viewProjection(0,1);
    planes[RBPlane::PF_RIGHT].Normal(2) = viewProjection(3,2) - viewProjection(0,2);
    planes[RBPlane::PF_RIGHT].Distance  = viewProjection(3,3) - viewProjection(0,3);
    RBPlane::Normalize(&planes[RBPlane::PF_RIGHT]);

    // Top plane
    planes[RBPlane::PF_TOP].Normal(0) = viewProjection(3,0) - viewProjection(1,0);
    planes[RBPlane::PF_TOP].Normal(1) = viewProjection(3,1) - viewProjection(1,1);
    planes[RBPlane::PF_TOP].Normal(2) = viewProjection(3,2) - viewProjection(1,2);
    planes[RBPlane::PF_TOP].Distance  = viewProjection(3,3) - viewProjection(1,3);
    RBPlane::Normalize(&planes[RBPlane::PF_TOP]);

    // Bottom plane
    planes[RBPlane::PF_BOTTOM].Normal(0) = viewProjection(3,0) + viewProjection(1,0);
    planes[RBPlane::PF_BOTTOM].Normal(1) = viewProjection(3,1) + viewProjection(1,1);
    planes[RBPlane::PF_BOTTOM].Normal(2) = viewProjection(3,2) + viewProjection(1,2);
    planes[RBPlane::PF_BOTTOM].Distance  = viewProjection(3,3) + viewProjection(1,3);
    RBPlane::Normalize(&planes[RBPlane::PF_BOTTOM]);

    // Near plane
    planes[RBPlane::PF_NEAR].Normal(0) = viewProjection(3,0) + viewProjection(2,0);
    planes[RBPlane::PF_NEAR].Normal(1) = viewProjection(3,1) + viewProjection(2,1);
    planes[RBPlane::PF_NEAR].Normal(2) = viewProjection(3,2) + viewProjection(2,2);
    planes[RBPlane::PF_NEAR].Distance  = viewProjection(3,3) + viewProjection(2,3);
    RBPlane::Normalize(&planes[RBPlane::PF_NEAR]);

    // Far plane
    planes[RBPlane::PF_FAR].Normal(0) = viewProjection(3,0) - viewProjection(2,0);
    planes[RBPlane::PF_FAR].Normal(1) = viewProjection(3,1) - viewProjection(2,1);
    planes[RBPlane::PF_FAR].Normal(2) = viewProjection(3,2) - viewProjection(2,2);
    planes[RBPlane::PF_FAR].Distance  = viewProjection(3,3) - viewProjection(2,3);
    RBPlane::Normalize(&planes[RBPlane::PF_FAR]);

}

}